﻿using System;
using System.Collections.Generic;
using System.Net;
using System.IO;

namespace Communicate
{
    /// <summary>
    /// 服务管理。
    /// </summary>
    public class Proxy
    {
        static Dictionary<Type, object> cacheInstance = new Dictionary<Type, object>();
        static CookieContainer cookieContainer = null;
        static string userName, password, url;
        public static event Action LoginSuccess;
        /// <summary>
        /// 获取数据处理接口。
        /// </summary>
        /// <typeparam name="T">接口类型。</typeparam>
        /// <returns>数据处理接口实例。</returns>
        public static T GetInstance<T>()
        {
            return (T)GetInstance(typeof(T));
        }
        /// <summary>
        /// 获取数据处理接口。
        /// </summary>
        /// <param name="type">接口类型。</param>
        /// <returns>数据处理接口实例。</returns>
        public static object GetInstance(Type type)
        {
            if (cookieContainer == null)
                throw new Exception("请先调用 Proxy.Login 进行登录！");
            if (!cacheInstance.ContainsKey(type))
                cacheInstance.Add(type, Transmit.CreateInterface(type));
            return cacheInstance[type];
        }
        /// <summary>
        /// 登录。
        /// </summary>
        /// <param name="userName">用户名。</param>
        /// <param name="password">密码。</param>
        /// <param name="url">服务器地址。</param>
        /// <returns>是否登录成功。</returns>
        public static LoginResult Login(string userName, string password, string url)
        {
            if (!url.EndsWith("/"))
                url += "/";
            if (string.IsNullOrEmpty(userName))
                throw new Exception("登录的用户名不能为空！");
            Proxy.userName = userName;
            Proxy.password = password;
            Proxy.url = url;
            if (cookieContainer == null)
            {
                cookieContainer = new CookieContainer();
            }
            LoginResult result = (LoginResult)Serializer.Deserialize(RequestData(Serializer.Serialize(new LoginRequest() { UserName = userName, Password = password })));
            if (!result.Result)
                cookieContainer = null;
            else
            {
                if (LoginSuccess != null)
                    LoginSuccess();
            }
            return result;
        }
        /// <summary>
        /// 注销登录。
        /// </summary>
        public static void Logout()
        {
            cookieContainer = new CookieContainer();
        }
        static byte[] RequestData(byte[] data)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url + "WebServiceHandler.axd");
            request.CookieContainer = cookieContainer;
            request.Method = "POST";
            request.Accept = "*/*";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;
            request.GetRequestStream().Write(data, 0, data.Length);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream stream = response.GetResponseStream();
            byte[] result = new byte[response.ContentLength];
            int readecount = 0;
            while (readecount < (int)response.ContentLength)
            {
                readecount += stream.Read(result, readecount, (int)response.ContentLength - readecount);
            }
            return result;
        }
        // 访问服务。
        internal static object InvokeMember(string type, string method, object[] param)
        {
            InvokeEntity entyty = new InvokeEntity() { Interfaces = type, Method = method, Parameters = param };
            object obj = Serializer.Deserialize(RequestData(Serializer.Serialize(entyty)));
            if (obj is CommunicateException)
            {
                CommunicateException ex = (CommunicateException)obj;
                if (ex.ExceptionType == ExceptionType.Timeout)
                {
                    var loginResult = Login(userName, password, url);
                    if (loginResult.Result)
                    {
                        obj = Serializer.Deserialize(RequestData(Serializer.Serialize(entyty)));
                        if (obj is CommunicateException)
                            throw new Exception(((CommunicateException)obj).Message, new Exception(((CommunicateException)obj).Detailed));
                    }
                    else
                        throw new Exception("重新登录失败：" + loginResult.Message);
                }
                else
                {
                    throw new Exception(ex.Message, new Exception(ex.Detailed));
                }
            }
            return obj;
        }
    }
}
